<template>
  <div id="container"></div>
  <SelectFolder @on-selected="loadGLTF"></SelectFolder>
  <div class="animations" v-if="animations.length">
    播放：
    <div
      v-for="item in animations"
      :key="item.uuid"
      class="animation"
      @click="playAnimation(item)"
    >
      {{ item.name }}
    </div>
  </div>
</template>

<script lang="ts" setup>
import * as THREE from "three";
import { GLTFLoader, type GLTF } from "three/addons/loaders/GLTFLoader";
import { OrbitControls } from "three/addons/controls/OrbitControls";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import { onMounted, shallowRef } from "vue";
import SelectFolder from "./SelectFolder.vue";

let scene: THREE.Scene;
let camera: THREE.PerspectiveCamera;

let currentModel: GLTF;

const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath(
  "https://www.gstatic.com/draco/versioned/decoders/1.5.6/"
);

dracoLoader.setDecoderConfig({ type: "js" }); //使用js方式解压
dracoLoader.preload(); //初始化_initDecoder 解码器
loader.setDRACOLoader(dracoLoader); //gltfloader使用dracoLoader

let animations = shallowRef<THREE.AnimationClip[]>([]);
let mixer: THREE.AnimationMixer;
let clock = new THREE.Clock();

let loadGLTF = (url: string) => {
  loader.load(url, function (gltf) {
    if (currentModel) {
      scene.remove(currentModel.scene);
    }
    currentModel = gltf;

    scene.add(gltf.scene);

    mixer = new THREE.AnimationMixer(gltf.scene);
    animations.value = gltf.animations;
    let { x, y, z } = new THREE.Box3().setFromObject(gltf.scene).max;

    //设置相机
    camera.position.set(x + 1, y + 1, z + 1);
    camera.lookAt(0, 0, 0);
  });
};

function playAnimation(animation: THREE.AnimationClip) {
  mixer.clipAction(animation).play();
}
onMounted(() => {
  scene = new THREE.Scene();
  scene.background = new THREE.Color("skyblue");

  camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );

  const renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  let container = document.getElementById("container");
  container!.appendChild(renderer.domElement);

  const light = new THREE.AmbientLight(0xffffff, 1);
  scene.add(light);

  const controls = new OrbitControls(camera, renderer.domElement);

  function animate() {
    if (mixer) {
      const delta = clock.getDelta();
      mixer.update(delta);
    }
    controls.update();
    renderer.render(scene, camera);
    requestAnimationFrame(animate);
  }
  animate();
});
</script>

<style>
#container {
  position: absolute;
  width: 100%;
  height: 100%;
}

.animations {
  position: absolute;
  bottom: 10px;
  display: flex;
  justify-content: center;
  width: 100%;
}
.animation {
  cursor: pointer;
  margin-right: 10px;
}
</style>
